﻿using AspNetCoreRateLimit;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.Extensions.DependencyInjection;
using My.Core.Startup;
using My.Framework;
using My.Framework.AspNetCore;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.RateLimiting;
using System.Threading.Tasks;

namespace My.Core.IPRate
{
	/// <summary>
	/// IP和速率限制
	/// </summary>
	public class IPRateStartup : StartupModule<IPRateStartup>
	{
		/// <summary>
		/// 程序启动器
		/// </summary>
		public IPRateStartup() => Order = 1;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="webApplicationBuilder"></param>
		public override void ConfigureServices(WebApplicationBuilder webApplicationBuilder)
		{
			var services = webApplicationBuilder.Services;

			//从appsettings.json中加载常规配置，IpRateLimiting与配置文件中节点对应
			services.Configure<IpRateLimitOptions>(webApplicationBuilder.Configuration.GetSection("IpRateLimiting"));

			//从appsettings.json中加载Ip规则
			services.Configure<IpRateLimitPolicies>(webApplicationBuilder.Configuration.GetSection("IpRateLimitPolicies"));
			//注入计数器和规则存储
			services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
			services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
			//配置（解析器、计数器密钥生成器）
			services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
			services.AddSingleton<IProcessingStrategy, AsyncKeyLockProcessingStrategy>();

			// 速率限制
			services.AddRateLimiter(_ => _
			// 固定窗口限流器，下面设置表示在这个窗口内（12秒），可以最多有6个请求，4个会被处理，2个则在排队，其他的则会在一定时间后拒绝返回
			.AddFixedWindowLimiter(policyName: "fixed", options =>
			{
				options.PermitLimit = 4;    // 每窗口允许最多请求数,设为4
				options.Window = TimeSpan.FromSeconds(12);  // 每窗口的时间，单位秒
				options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;    // 排队请求的处理顺序,优先处理先来的请求
				options.QueueLimit = 2; // 当窗口请求数达到最大时，后续请求会进入排队，用于设置队列的大小，设为2
			}));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="webApplication"></param>
		public override void Configure(WebApplication webApplication)
		{
			//启用客户端IP限制速率
			webApplication.UseIpRateLimiting();
			webApplication.UseRateLimiter();
		}
	}
}
